﻿using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Collections.Concurrent;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MicrosoftWebSocket2._0Server.Core
{

    public class WebSockSvr
    {
        public ConcurrentDictionary<string, WebSocket> ClinetList { get; set; } 
            = new ConcurrentDictionary<string, WebSocket>();
        IWebHost server;
        public WebSockSvr()
        {
            var builder = WebHost.CreateDefaultBuilder();
            builder
            .ConfigureKestrel((opts => 
            {
                opts.ListenAnyIP(4040);
            }))
            .ConfigureServices(services => 
            {
            })
            .Configure((app) =>
            {
                app.UseWebSockets(new WebSocketOptions
                {
                    KeepAliveInterval = TimeSpan.FromSeconds(60),
                });
                app.Use(async (context, next) =>
                {
                    if (!context.WebSockets.IsWebSocketRequest)
                    {
                        await next.Invoke();
                        return;
                    }
                    var id = Guid.NewGuid().ToString("N");
                    try
                    {
                        var socket = await context.WebSockets.AcceptWebSocketAsync();

                        var buffer = new ArraySegment<byte>(new byte[1024]);
                        ClinetList.TryAdd(id, socket);
                        while (socket.State == WebSocketState.Open)
                        {
                            var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
                            if (result.MessageType == WebSocketMessageType.Close)
                            {
                                throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, result.CloseStatusDescription);
                            }
                            var text = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
                            var sendStr = Encoding.UTF8.GetBytes($"Echo: {text}");
                            await socket.SendAsync(new ArraySegment<byte>(sendStr), WebSocketMessageType.Text, true, CancellationToken.None);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"WebSocket has exception, {ex.Message}\r\n{ex.StackTrace}");
                    }
                    finally
                    {
                        ClinetList.TryRemove(id, out _);
                    }
                });
            });
            server = builder.Build();
        }

        public void Start()
        {
            server.Start();
        }

        public void SendDatas()
        {
            for (int i = 0; i < 200; i++)
            {
                Task.Run(async () =>
                {
                    while (true)
                    {
                        try
                        {
                            foreach (var client in ClinetList)
                            {
                                var sock = client.Value;
                                if (sock.State == WebSocketState.Open)
                                {
                                    var sendStr = Encoding.UTF8.GetBytes($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]");
                                    await sock.SendAsync(new ArraySegment<byte>(sendStr), WebSocketMessageType.Text, true, CancellationToken.None);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"SendDatas has exception,{ex.Message}\r\n{ex.StackTrace}");
                        }
                        finally
                        {
                            await Task.Delay(10);
                        }
                    }
                });
            }
        }
    }
}
